package cc.zy.base.businesses.utils;

import cc.zy.base.businesses.entity.ReqResultExtension;
import cc.zy.base.businesses.entity.SignatureRegistration;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.BeanUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.LinkedHashMap;

public class StepUtilLZ {

//    public static void main(String[] args) {
//
//        String userName = "胡腾娇";
//        String idCard = "130582199606193014";
//        String phone = "15529056690";
//
//        // 请求签名鉴权-创建学生ID
//        String userId =  createUserId(userName, idCard, phone);
//        // 请求签名鉴权-通过模板创建签署文件
//        String fileId  = createFileId(userName, idCard, phone);
//        // 请求签名鉴权-发起一步签署
//        String flowId = createOneStep(fileId, userId);
//
//    }

    public static void testPrint(StepProperties properties) {
        System.out.println("请求返回信息： " + properties.getPosOneX());
    }

    /***
     * 请求签名鉴权-POST请求创建用户ID
     *
     * @param student
     * @param properties
     */
    public static String createUserId(ReqResultExtension student, StepPropertiesLZ properties) {

        // 个人创建账号接口地址
        String accountsApi = "/v1/accounts/createByThirdPartyUserId";
        // 个人创建账号接口请求地址
        String accountsApiUrl = properties.getHost() + accountsApi;

        try {
            // 构建请求Body体
            JSONObject reqBodyObj = new JSONObject();
            reqBodyObj.put("thirdPartyUserId", student.getTel());
            reqBodyObj.put("name", student.getStuName());
            reqBodyObj.put("idType", "CRED_PSN_CH_IDCARD");
            reqBodyObj.put("idNumber", student.getIdentity());
            reqBodyObj.put("mobile", student.getTel());

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = doContentMD5(reqBodyData);

            // 构建待签名字符串
            String method = "POST";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = accountsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, properties.getAppKey());

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", properties.getAppId());
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendPOST(accountsApiUrl, reqBodyData, header, "UTF-8");
            JSONObject resultObj = JSONObject.fromObject(result);
            System.out.println("请求返回信息： " + resultObj.toString());
            System.out.println("请求返回信息： " + resultObj.getJSONObject("data").getString("accountId"));
            return resultObj.getJSONObject("data").getString("accountId");
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }
    }

    /***
     * 请求签名鉴权-POST请求通过模板创建文件
     *
     * @param student
     * @param registration
     * @param properties
     */
    public static String createFileId(ReqResultExtension student, SignatureRegistration registration, Object setProperties) {
        AllProperties properties = new AllProperties();

        BeanUtils.copyProperties(setProperties, properties);

        // 个人创建账号接口地址
        String fileApi = "/v1/files/createByTemplate";
        // 个人创建账号接口请求地址
        String fileApiUrl = properties.getHost() + fileApi;

        try {
            // 构建请求Body体
            JSONObject reqBodyObj = new JSONObject();
            JSONObject reqBodyObjFormFields = new JSONObject();
            reqBodyObj.put("name", properties.getFileName() + ".pdf");
            reqBodyObjFormFields.put(properties.getUserKeyOne(), student.getStuName());
            reqBodyObjFormFields.put(properties.getUserKeyTwo(), student.getStuName());
            reqBodyObjFormFields.put(properties.getTel(), student.getTel());
            reqBodyObjFormFields.put(properties.getSchool(), student.getCollegeName());
            reqBodyObjFormFields.put(properties.getLevel(), student.getLevelName());
            reqBodyObjFormFields.put(properties.getMajor(), student.getMajorName());
            reqBodyObjFormFields.put(properties.getTeacher(), student.getUserName());
            reqBodyObjFormFields.put(properties.getIdentity(), student.getIdentity());
            reqBodyObjFormFields.put(properties.getAddress(), student.getAddress());
            reqBodyObjFormFields.put(properties.getCost(), Double.parseDouble( registration.getCost().toString()));
            reqBodyObjFormFields.put(properties.getCostBlock(), registration.getCostBlock());
            reqBodyObjFormFields.put(properties.getRemark(), "本人已认真阅读以上条款内容，对协议内容无异议，确认报名。");
            reqBodyObj.put("simpleFormFields",reqBodyObjFormFields);
            reqBodyObj.put("templateId",properties.getTemplateId());

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = doContentMD5(reqBodyData);

            // 构建待签名字符串
            String method = "POST";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = fileApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, properties.getAppKey());

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", properties.getAppId());
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendPOST(fileApiUrl, reqBodyData, header, "UTF-8");
            JSONObject resultObj = JSONObject.fromObject(result);
            System.out.println("请求返回信息： " + resultObj.toString());
            System.out.println("请求返回信息： " + resultObj.getJSONObject("data").getString("fileId"));
            return resultObj.getJSONObject("data").getString("fileId");
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }
    }


    /***
     * 请求签名鉴权-POST请求一步发起签署
     *
     * @param fileId
     * @param userId
     * @param properties
     */
    public static String createOneStep(String fileId, String userId, Object setProperties, String pages) {
        AllProperties properties = new AllProperties();

        BeanUtils.copyProperties(setProperties, properties);

        // 个人创建账号接口地址
        String oneStepApi = "/api/v2/signflows/createFlowOneStep";
        // 个人创建账号接口请求地址
        String oneStepUrl = properties.getHost() + oneStepApi;

        try {
            // 构建请求Body体
            JSONObject reqBodyObj = new JSONObject();

            JSONObject attachments = new JSONObject();
            attachments.put("attachmentName","1");
            attachments.put("fileId",fileId); // 通过模板生成的文件
            JSONArray attachmentsArray =  new JSONArray();
            attachmentsArray.add(attachments);
            reqBodyObj.put("attachments",attachmentsArray);

//            JSONObject copiers = new JSONObject();
//            copiers.put("copierAccountId",userId); // 个人账号
//            copiers.put("copierIdentityAccountId",userId); // 个人账号
//            copiers.put("copierIdentityAccountType",0);
//            JSONArray copiersArray =  new JSONArray();
//            copiersArray.add(copiers);
//            reqBodyObj.put("copiers",copiersArray);

            JSONObject docs = new JSONObject();
            docs.put("fileId",fileId);
            docs.put("fileName",properties.getFileName());
            JSONArray docsArray =  new JSONArray();
            docsArray.add(docs);
            reqBodyObj.put("docs",docsArray);

            JSONObject flowInfo = new JSONObject();
            flowInfo.put("autoArchive",true);
            flowInfo.put("autoInitiate",true);
            flowInfo.put("businessScene",properties.getFileName());
            JSONObject flowConfigInfo = new JSONObject();
            flowConfigInfo.put("batchDropSeal",false);
            flowConfigInfo.put("noticeType","1");
            flowConfigInfo.put("noticeDeveloperUrl",properties.getStepCallBackUrl());//回调接口配置
            flowConfigInfo.put("redirectUrl","");//签署完成重定向地址
            flowInfo.put("flowConfigInfo",flowConfigInfo);
            flowInfo.put("initiatorAccountId", properties.getAccountId());//发起方账户id
            reqBodyObj.put("flowInfo",flowInfo);

            JSONObject signer1 = new JSONObject();
            signer1.put("platformSign",true);
            JSONObject signfields1 = new JSONObject();
            signfields1.put("actorIndentityType","2");
            signfields1.put("autoExecute",true);
            signfields1.put("fileId",fileId);
            JSONObject posBean1 = new JSONObject();
            posBean1.put("posPage",pages);
            posBean1.put("posX",properties.getPosOneX());
            posBean1.put("posY",properties.getPosOneY());
            signfields1.put("posBean",posBean1);
            JSONObject signDateBean1 = new JSONObject();
            signDateBean1.put("fontSize",15);
            signDateBean1.put("format","yyyy年MM月dd日");
            signDateBean1.put("posPage",pages);
            signDateBean1.put("posX",properties.getPosOneDateX());
            signDateBean1.put("posY",properties.getPosOneDateY());
            signfields1.put("signDateBean", signDateBean1);
            signfields1.put("signDateBeanType",1);
            JSONArray signfields1Array =  new JSONArray();
            signfields1Array.add(signfields1);
            signer1.put("signfields",signfields1Array);


            JSONObject signer2 = new JSONObject();
            signer2.put("platformSign",false);
            JSONObject signerAccount = new JSONObject();
            signerAccount.put("authorizedAccountId",userId);
            signerAccount.put("signerAccountId",userId);
            signer2.put("signerAccount",signerAccount);
            JSONObject signfields2 = new JSONObject();
            signfields2.put("actorIndentityType","0");
            signfields2.put("autoExecute",false);
            signfields2.put("fileId",fileId);
            JSONObject posBean2 = new JSONObject();
            posBean2.put("posPage",pages);
            posBean2.put("posX",properties.getPosTwoX());
            posBean2.put("posY",properties.getPosTwoY());
            signfields2.put("posBean",posBean2);
            JSONObject signDateBean2 = new JSONObject();
            signDateBean2.put("fontSize",15);
            signDateBean2.put("format","yyyy年MM月dd日");
            signDateBean2.put("posPage",pages);
            signDateBean2.put("posX",properties.getPosTwoDateX());
            signDateBean2.put("posY",properties.getPosTwoDateY());
            signfields2.put("signDateBean", signDateBean2);
            signfields2.put("signDateBeanType",1);
            signer2.put("signOrder",2);
            JSONArray signfields2Array =  new JSONArray();
            signfields2Array.add(signfields2);
            signer2.put("signfields",signfields2Array);

            JSONObject signer3 = new JSONObject();
            signer3.put("platformSign",true);
            JSONObject signfields3 = new JSONObject();
            signfields3.put("actorIndentityType","2");
            signfields3.put("autoExecute",true);
            signfields3.put("fileId",fileId);
            signfields3.put("signType",2);
            JSONObject posBean3 = new JSONObject();
            if("5".equals(pages))
            {
                posBean3.put("posPage","1-2-3-4-5");
            }
            if("6".equals(pages))
            {
                posBean3.put("posPage","1-2-3-4-5-6");
            }
            posBean3.put("posX",properties.getPosThreeX());
            posBean3.put("posY",properties.getPosThreeY());
            signfields3.put("posBean",posBean3);
            JSONArray signfields3Array =  new JSONArray();
            signfields3Array.add(signfields3);
            signer3.put("signfields",signfields3Array);


            JSONArray signersArray = new JSONArray();
            signersArray.add(signer1);
            signersArray.add(signer2);
            signersArray.add(signer3);


            reqBodyObj.put("signers",signersArray);

//            String json = "{\"attachments\":[{\"attachmentName\":\"1\",\"fileId\":\"348b13be9e7148db955773d585cf0cb8\"}],\"copiers\":[{\"copierAccountId\":\"9d3df48717634a43aa2c2e5cedaf780f\",\"copierIdentityAccountId\":\"9d3df48717634a43aa2c2e5cedaf780f\",\"copierIdentityAccountType\":0}],\"docs\":[{\"fileId\":\"348b13be9e7148db955773d585cf0cb8\",\"fileName\":\"测试合同.pdf\",\"filePassword\":\"\"}],\"flowInfo\":{\"autoArchive\":false,\"autoInitiate\":true,\"businessScene\":\"测试合同\",\"flowConfigInfo\":{\"batchDropSeal\":false,\"billIsolationCode\":\"\",\"faceVideoTemplate\":\"\",\"noticeDeveloperUrl\":\"\",\"noticeType\":\"1\",\"orgAvailableAuthTypes\":[],\"personAuthAdvancedEnabled\":[],\"personAvailableAuthTypes\":[],\"redirectUrl\":\"\",\"signPlatform\":\"\",\"willTypes\":[]},\"initiatorAccountId\":\"\",\"initiatorAuthorizedAccountId\":\"\",\"remark\":\"\"},\"signers\":[{\"platformSign\":true,\"signerAccount\":{\"authorizedAccountId\":\"\",\"signerAccountId\":\"\"},\"signfields\":[{\"actorIndentityType\":\"2\",\"assignedPosbean\":\"\",\"autoExecute\":true,\"fileId\":\"348b13be9e7148db955773d585cf0cb8\",\"posBean\":{\"posPage\":\"5\",\"posX\":438.156,\"posY\":433.462},\"sealId\":\"\",\"sealType\":\"\",\"signDateBean\":{\"fontSize\":15,\"format\":\"yyyy年MM月dd日\",\"posPage\":5,\"posX\":388.156,\"posY\":383.462},\"signDateBeanType\":1}],\"thirdOrderNo\":\"\"},{\"platformSign\":false,\"signerAccount\":{\"authorizedAccountId\":\"9d3df48717634a43aa2c2e5cedaf780f\",\"signerAccountId\":\"9d3df48717634a43aa2c2e5cedaf780f\"},\"signfields\":[{\"actorIndentityType\":\"0\",\"assignedPosbean\":\"\",\"autoExecute\":false,\"fileId\":\"348b13be9e7148db955773d585cf0cb8\",\"posBean\":{\"posPage\":\"5\",\"posX\":229.156,\"posY\":432.453},\"sealId\":\"\",\"sealType\":\"\",\"signDateBean\":{\"fontSize\":15,\"format\":\"yyyy年MM月dd日\",\"posPage\":5,\"posX\":179.156,\"posY\":382.453},\"signDateBeanType\":1}],\"signOrder\":2,\"thirdOrderNo\":\"\"}]}";

            // 请求Body体数据
            String reqBodyData = reqBodyObj.toString();
//            String reqBodyData = json;
            // 对请求Body体内的数据计算ContentMD5
            String contentMD5 = doContentMD5(reqBodyData);

            // 构建待签名字符串
            String method = "POST";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = oneStepApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, properties.getAppKey());

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", properties.getAppId());
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendPOST(oneStepUrl, reqBodyData, header, "UTF-8");
            JSONObject resultObj = JSONObject.fromObject(result);
            System.out.println("请求返回信息： " + resultObj.toString());
            System.out.println("请求返回信息： " + resultObj.getJSONObject("data").getString("flowId"));
            return resultObj.getJSONObject("data").getString("flowId");
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }
    }

    /***
     * 请求签名鉴权-GET请求
     *
     * @param flowId
     * @param properties
     */
    public static String getFlowFile(String flowId, StepPropertiesLZ properties) {
        // 查询个人印章接口
        String getPersonSealsApi = "/v1/signflows/" + flowId + "/documents";
        // 查询个人印章接口请求地址
        String getPersonSealsApi_Url = properties.getHost() + getPersonSealsApi;

        try {
            // GET请求时ContentMD5为""
            String contentMD5 = "{}";

            // 构建待签名字符串
            String method = "GET";
            String accept = "*/*";
            String contentType = "application/json; charset=UTF-8";
            String url = getPersonSealsApi;
            String date = "";
            String headers = "";

            StringBuffer sb = new StringBuffer();
            sb.append(method).append("\n").append(accept).append("\n").append(contentMD5).append("\n")
                    .append(contentType).append("\n").append(date).append("\n");
            if ("".equals(headers)) {
                sb.append(headers).append(url);
            } else {
                sb.append(headers).append("\n").append(url);
            }

            // 构建参与请求签名计算的明文
            String plaintext = sb.toString();
            // 计算请求签名值
            String reqSignature = doSignatureBase64(plaintext, properties.getAppKey());

            // 获取时间戳(精确到毫秒)
            long timeStamp = timeStamp();

            // 构建请求头
            LinkedHashMap<String, String> header = new LinkedHashMap<String, String>();
            header.put("X-Tsign-Open-App-Id", properties.getAppId());
            header.put("X-Tsign-Open-Auth-Mode", "Signature");
            header.put("X-Tsign-Open-Ca-Timestamp", String.valueOf(timeStamp));
            header.put("Accept", accept);
            header.put("Content-Type", contentType);
            header.put("X-Tsign-Open-Ca-Signature", reqSignature);
            header.put("Content-MD5", contentMD5);

            // 发送POST请求
            String result = HTTPHelper.sendGet(getPersonSealsApi_Url, header, "UTF-8");
            JSONObject resultObj = JSONObject.fromObject(result);
            System.out.println("请求返回信息： " + resultObj.toString());
            System.out.println("签署完成后文档地址为： " + resultObj.getJSONObject("data").getJSONArray("docs").getJSONObject(0).getString("fileUrl"));
            return resultObj.getJSONObject("data").getJSONArray("docs").getJSONObject(0).getString("fileUrl");
        } catch (Exception e) {
            e.printStackTrace();
            String msg = MessageFormat.format("请求签名鉴权方式调用接口出现异常: {0}", e.getMessage());
            System.out.println(msg);
            return null;
        }
    }

    /***
     *
     * @param str 待计算的消息
     * @return MD5计算后摘要值的Base64编码(ContentMD5)
     * @throws Exception 加密过程中的异常信息
     */
    public static String doContentMD5(String str) throws Exception {
        byte[] md5Bytes = null;
        MessageDigest md5 = null;
        String contentMD5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md5.update(str.getBytes("UTF-8"));
            // 获取文件MD5的二进制数组（128位）
            md5Bytes = md5.digest();
            // 把MD5摘要后的二进制数组md5Bytes使用Base64进行编码（而不是对32位的16进制字符串进行编码）
            contentMD5 = new String(Base64.encodeBase64(md5Bytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return contentMD5;
    }

    /***
     * 计算请求签名值
     *
     * @param message 待计算的消息
     * @param secret 密钥
     * @return HmacSHA256计算后摘要值的Base64编码
     * @throws Exception 加密过程中的异常信息
     */
    public static String doSignatureBase64(String message, String secret) throws Exception {
        String algorithm = "HmacSHA256";
        Mac hmacSha256;
        String digestBase64 = null;
        try {
            hmacSha256 = Mac.getInstance(algorithm);
            byte[] keyBytes = secret.getBytes("UTF-8");
            byte[] messageBytes = message.getBytes("UTF-8");
            hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
            // 使用HmacSHA256对二进制数据消息Bytes计算摘要
            byte[] digestBytes = hmacSha256.doFinal(messageBytes);
            // 把摘要后的结果digestBytes转换成十六进制的字符串
            // String digestBase64 = Hex.encodeHexString(digestBytes);
            // 把摘要后的结果digestBytes使用Base64进行编码
            digestBase64 = new String(Base64.encodeBase64(digestBytes), "UTF-8");
        } catch (NoSuchAlgorithmException e) {
            String msg = MessageFormat.format("不支持此算法: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (UnsupportedEncodingException e) {
            String msg = MessageFormat.format("不支持的字符编码: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        } catch (InvalidKeyException e) {
            String msg = MessageFormat.format("无效的密钥规范: {0}", e.getMessage());
            Exception ex = new Exception(msg);
            ex.initCause(e);
            throw ex;
        }
        return digestBase64;
    }

    /***
     * 获取时间戳(毫秒级)
     *
     * @return 毫秒级时间戳,如 1578446909000
     */
    public static long timeStamp() {
        long timeStamp = System.currentTimeMillis();
        return timeStamp;
    }

    /**
     * 汉语中数字大写
     */
    private static final String[] CN_UPPER_NUMBER = {"零", "壹", "贰", "叁", "肆",
            "伍", "陆", "柒", "捌", "玖"};
    /**
     * 汉语中货币单位大写，这样的设计类似于占位符
     */
    private static final String[] CN_UPPER_MONETRAY_UNIT = {"分", "角", "元",
            "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾",
            "佰", "仟"};
    /**
     * 特殊字符：整
     */
    private static final String CN_FULL = "整";
    /**
     * 特殊字符：负
     */
    private static final String CN_NEGATIVE = "负";
    /**
     * 金额的精度，默认值为2
     */
    private static final int MONEY_PRECISION = 2;
    /**
     * 特殊字符：零元整
     */
    //private static final String CN_ZEOR_FULL = "零元" + CN_FULL;
    private static final String CN_ZEOR_FULL = "零";
    /**
     * 把输入的金额转换为汉语中人民币的大写
     *
     * @param numberOfMoney 输入的金额
     * @return 对应的汉语大写
     */
    public static String number2CNMontrayUnit(BigDecimal numberOfMoney) {
        StringBuffer sb = new StringBuffer();
        // -1, 0, or 1 as the value of this BigDecimal is negative, zero, or
        // positive.
        int signum = numberOfMoney.signum();
        // 零元整的情况
        if (signum == 0) {
            return CN_ZEOR_FULL;
        }
        // 这里会进行金额的四舍五入
        long number = numberOfMoney.movePointRight(MONEY_PRECISION)
                .setScale(0, 4).abs().longValue();
        // 得到小数点后两位值
        long scale = number % 100;
        int numUnit = 0;
        int numIndex = 0;
        boolean getZero = false;
        // 判断最后两位数，一共有四中情况：00 = 0, 01 = 1, 10, 11
        if (!(scale > 0)) {
            numIndex = 2;
            number = number / 100;
            getZero = true;
        }
        if ((scale > 0) && (!(scale % 10 > 0))) {
            numIndex = 1;
            number = number / 10;
            getZero = true;
        }
        int zeroSize = 0;
        while (true) {
            if (number <= 0) {
                break;
            }
            // 每次获取到最后一个数
            numUnit = (int) (number % 10);
            if (numUnit > 0) {
                if ((numIndex == 9) && (zeroSize >= 3)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[6]);
                }
                if ((numIndex == 13) && (zeroSize >= 3)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[10]);
                }
                sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                sb.insert(0, CN_UPPER_NUMBER[numUnit]);
                getZero = false;
                zeroSize = 0;
            } else {
                ++zeroSize;
                if (!(getZero)) {
                    sb.insert(0, CN_UPPER_NUMBER[numUnit]);
                }
                if (numIndex == 2) {
                    if (number > 0) {
                        sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                    }
                } else if (((numIndex - 2) % 4 == 0) && (number % 1000 > 0)) {
                    sb.insert(0, CN_UPPER_MONETRAY_UNIT[numIndex]);
                }
                getZero = true;
            }
            // 让number每次都去掉最后一个数
            number = number / 10;
            ++numIndex;
        }
        // 如果signum == -1，则说明输入的数字为负数，就在最前面追加特殊字符：负
        if (signum == -1) {
            sb.insert(0, CN_NEGATIVE);
        }
        // 输入的数字小数点后两位为"00"的情况，则要在最后追加特殊字符：整
//        if (!(scale > 0)) {
//            sb.append(CN_FULL);
//        }
        return sb.toString().replace("元","");
    }

}